
%token_type {token} 
%token_prefix    T_
%extra_argument {scompiler* compiler}

%left AND.
%left OR.
%nonassoc EQ NE GT GE LT LE.
%left PLUS MINUS.
%left TIMES DIVIDE MOD.
%right NOT.

%include {   
#include "parser.h"
#include "assert.h"
#include "compiler.h"
}  

%syntax_error {  
	printf("Snytax error\n");
}   
//
// complete template
//
start ::= template. 

//
// loop over template elements
//
// single template element
template ::= template_element. 

// loop of elements
template  ::= template template_element. 

// empty template
template       ::= . 

// comments
template_element::= COMMENT. 

//smarty tag
template_element::= smartytag.

template_element::= INNER_HTML(B). 
{
	int arg = append_sconst(compiler, svalue(B.val));
	add_iopcode(compiler, OP_SLOAD, arg);
	add_iopcode(compiler, OP_ECHO, 0);
	free(svalue(B.val));
}
//literal
smartytag ::= LDEL INNER_HTML(B).
{
	int arg = append_sconst(compiler, svalue(B.val));
	add_iopcode(compiler, OP_SLOAD, arg);
	add_iopcode(compiler, OP_ECHO, 0);
	free(svalue(B.val));
}

smartytag ::= LDEL expr RDEL. 
{ 
	add_iopcode(compiler, OP_ECHO, 0);
}
/////////////////////if
smartytag ::= LDEL IF expr RDEL.
{
	add_iopcode(compiler, OP_IFGOTO, 0);
	open_tag(compiler, "if", compiler->ops_num - 1, 0);
}

smartytag ::= LDEL EIF RDEL.
{
	tag* t = top_tag(compiler);
	int pos = t->arg1;
	set_iopcode(compiler, pos , OP_IFGOTO, compiler->ops_num);
	close_tag(compiler, "if");
}
////////////////////foreach
smartytag ::= LDEL FOREACH VARIABLE(B) AS VARIABLE(K) DOUBLE_ARROW VARIABLE(C) RDEL.
{
	char rand_var[16];
	int b = tmp_variable(compiler, svalue(B.val));
	int c = tmp_variable(compiler, svalue(C.val));
	int k = tmp_variable(compiler, svalue(K.val));
	
	rand_variable(compiler, "foreach_it", rand_var);	
	
	int i = tmp_variable(compiler, rand_var);
	add_iopcode(compiler, OP_ILOAD, 0);
	add_iopcode(compiler, OP_STORE, i);
	add_iopcode(compiler, OP_LOAD, i);
	add_iopcode(compiler, OP_LOAD,  b);
	int func = append_sconst(compiler, "count");
	add_iopcode(compiler, OP_CALL, func);
	add_iopcode(compiler, OP_GE, 0);
	add_iopcode(compiler, OP_NOT, 0);
	add_iopcode(compiler, OP_IFGOTO, 0);
	open_tag(compiler, "foreach", compiler->ops_num - 1, i);
	add_iopcode(compiler, OP_LOAD,  b);
	add_iopcode(compiler, OP_LOAD,  i);
	add_iopcode(compiler, OP_FETCH2, 0);
	add_iopcode(compiler, OP_STORE, c);
	add_iopcode(compiler, OP_STORE, k);
}

smartytag ::= LDEL FOREACH VARIABLE(B) AS VARIABLE(C) RDEL.
{
	char rand_var[16];
	int b = tmp_variable(compiler, svalue(B.val));
	int c = tmp_variable(compiler, svalue(C.val));
	
	rand_variable(compiler, "foreach_it", rand_var);	
	
	int i = tmp_variable(compiler, rand_var);
	add_iopcode(compiler, OP_ILOAD, 0);
	add_iopcode(compiler, OP_STORE, i);
	add_iopcode(compiler, OP_LOAD, i);
	add_iopcode(compiler, OP_LOAD,  b);
	int func = append_sconst(compiler, "count");
	add_iopcode(compiler, OP_CALL, func);
	add_iopcode(compiler, OP_GE, 0);
	add_iopcode(compiler, OP_NOT, 0);
	add_iopcode(compiler, OP_IFGOTO, 0);
	open_tag(compiler, "foreach", compiler->ops_num - 1, i);
	add_iopcode(compiler, OP_LOAD,  b);
	add_iopcode(compiler, OP_LOAD,  i);
	add_iopcode(compiler, OP_FETCH, 0);
	add_iopcode(compiler, OP_STORE, c);
}

smartytag ::= LDEL EFOREACH RDEL.
{
	tag* t = top_tag(compiler);
	int pos = t->arg1;
	int b = t->arg2;
	add_iopcode(compiler, OP_LOAD, b);
	add_iopcode(compiler, OP_ILOAD, 1);
	add_iopcode(compiler, OP_PLUS, 0);
	add_iopcode(compiler, OP_STORE, b);
	add_iopcode(compiler, OP_JMP, pos - 5);
	set_iopcode(compiler, pos , OP_IFGOTO, compiler->ops_num);
	close_tag(compiler, "foreach");
}
//////////////for
smartytag ::= LDEL FOR VARIABLE(B) FROM INTEGER(C) TO INTEGER(D) RDEL.
{
	int b = tmp_variable(compiler, svalue(B.val));
	add_iopcode(compiler, OP_ILOAD, ivalue(C.val));
	add_iopcode(compiler, OP_STORE, b);
	add_iopcode(compiler, OP_LOAD, b);
	add_iopcode(compiler, OP_ILOAD, ivalue(D.val));
	add_iopcode(compiler, OP_GT, 0);
	add_iopcode(compiler, OP_NOT, 0);
	add_iopcode(compiler, OP_IFGOTO, 0);
	open_tag(compiler, "for", compiler->ops_num - 1, b);
	free(svalue(B.val));
}

smartytag ::= LDEL EFOR RDEL.
{
	tag* t = top_tag(compiler);
	int pos = t->arg1;
	int b = t->arg2;
	add_iopcode(compiler, OP_LOAD, b);
	add_iopcode(compiler, OP_ILOAD, 1);
	add_iopcode(compiler, OP_PLUS, 0);
	add_iopcode(compiler, OP_STORE, b);
	add_iopcode(compiler, OP_JMP, pos - 4);
	set_iopcode(compiler, pos , OP_IFGOTO, compiler->ops_num);
	close_tag(compiler, "for");
}

////////////////function call
smartytag ::= LDEL function_call RDEL.
function_call ::= LABEL(B) OPENP function_args CLOSEP.
{
	int arg = append_sconst(compiler, svalue(B.val));
	add_iopcode(compiler, OP_CALL, arg);
	free(svalue(B.val));
}

function_args ::= function_args COMMA expr.
function_args ::= expr.
function_args ::=.

smartytag ::= LDEL EFUNCTION RDEL.
/////////////////////assign
smartytag ::= LDEL VARIABLE(B) ASSIGN expr RDEL.
{
	int b = tmp_variable(compiler, svalue(B.val));
	add_iopcode(compiler, OP_STORE, b);
	free(svalue(B.val));
}
smartytag ::= LDEL VARIABLE(B) ASSIGN function_call RDEL.
{
	int b = tmp_variable(compiler, svalue(B.val));
	add_iopcode(compiler, OP_STORE, b);
	free(svalue(B.val));
}

////////////////math expression
expr ::= expr PLUS   expr.   {add_iopcode(compiler, OP_PLUS, 0);}  
expr ::= expr MINUS  expr.   {add_iopcode(compiler, OP_MINUS, 0);}  
expr ::= expr TIMES  expr.   {add_iopcode(compiler, OP_TIMES, 0);}  
expr ::= expr DIVIDE  expr.  {add_iopcode(compiler, OP_DIV, 0); }  
expr ::= expr MOD  expr.   {add_iopcode(compiler, OP_MOD, 0); }  
expr ::= expr AND expr. {add_iopcode(compiler, OP_AND, 0);}
expr ::= expr OR expr.{add_iopcode(compiler, OP_OR, 0);}
expr ::= expr EQ expr.{add_iopcode(compiler, OP_EQ, 0);}
expr ::= expr NE expr.{add_iopcode(compiler, OP_NE, 0);}
expr ::= expr GT expr.{add_iopcode(compiler, OP_GT, 0);}
expr ::= expr LT expr.{add_iopcode(compiler, OP_LT, 0);}
expr ::= expr GE expr.{add_iopcode(compiler, OP_GE, 0);}
expr ::= expr LE expr.{add_iopcode(compiler, OP_LE, 0);}
expr ::= NOT expr.{add_iopcode(compiler, OP_NOT, 0);}

expr(A) ::= OPENP expr(B) CLOSEP.{A=B;} 
expr ::= INTEGER(B). {add_iopcode(compiler, OP_ILOAD,ivalue(B.val)); } 
expr ::= MINUS INTEGER(B). {add_iopcode(compiler, OP_ILOAD, -ivalue(B.val));} 
expr ::= FLOAT(B). {add_fopcode(compiler,OP_FLOAD, fvalue(B.val)); } 
expr ::= MINUS FLOAT(B). {add_fopcode(compiler,OP_FLOAD, -fvalue(B.val));} 

expr ::= DSTRING(B). 
{
	int arg = append_sconst(compiler, svalue(B.val));
	add_iopcode(compiler, OP_SLOAD, arg);
	free(svalue(B.val));
} 

expr ::= VARIABLE(B) indexdef.
{
	int arg = tmp_variable(compiler, svalue(B.val));
	add_iopcode(compiler, OP_LOAD, arg);
	merge_opcode(compiler);
	free(svalue(B.val));
}
expr ::= MINUS VARIABLE(B) indexdef.
{
	int arg = tmp_variable(compiler, svalue(B.val));
	add_iopcode(compiler, OP_LOAD, arg);
	merge_opcode(compiler);
	add_iopcode(compiler, OP_NEG, 0);
	free(svalue(B.val));
}
indexdef ::= indexdef DOT LABEL(B). 
{
	int arg = append_sconst(compiler, svalue(B.val));
	add_tmp_iopcode(compiler, OP_SLOAD, arg);
	add_tmp_iopcode(compiler, OP_FETCH,  0);//call array get
	free(svalue(B.val));
}
indexdef ::= indexdef DOT VARIABLE(B).
{
	int b = tmp_variable(compiler, svalue(B.val));
	add_tmp_iopcode(compiler, OP_LOAD, b);
	add_tmp_iopcode(compiler, OP_FETCH,  0);//call array get
	free(svalue(B.val));
}
indexdef ::= indexdef OPENB INTEGER(B) CLOSEB.
{
	add_tmp_iopcode(compiler, OP_ILOAD, ivalue(B.val));
	add_tmp_iopcode(compiler, OP_FETCH,  0);//call array get
}
indexdef ::= .


